home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 June
/
EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso
/
earcd
/
cmdity
/
clicker.lha
/
Clicker
/
Source
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-17
|
10KB
|
369 lines
/* File: main.c
* Created: 01-01-95
* Updated: 17-05-96
* Version: 1.3
* Project: Clicker
* Owner: Jeroen Vermeulen
* Requirements: KickStart V39+
* Legal: PD
* Status: Release
*/
char verstr[]="$VER: Clicker 1.3 (17.05.96) Jeroen Vermeulen",
descrp[]="Clicker 1.3 - Public Domain";
/* TODO:
* Prefs save option!
* Add note names to frequency display
*/
#include <proto/exec.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/utility.h>
#include <proto/commodities.h>
#include <proto/gadtools.h>
#include <proto/alib.h>
#include <intuition/gadgetclass.h>
#include "main.h"
#include "broker.h"
#include "prefs.h"
#include "sound.h"
#include "gui.h"
STRPTR AllocFailMsgPort = "Unable to set up message port!\n",
OpenFailIconBase = "Need icon.library V36 or better\n",
OpenFailUtilBase = "Couldn't open utility.library\n",
OpenFailCommBase = "Couldn't open commodities.library\n",
OpenFailGadTBase = "Couldn't open gadtools.library\n";
static STRPTR Break_Exit = "**BREAK** -- Clicker removed\n";
struct UTILITYBASE *UtilityBase=NULL;
struct Library *CxBase=NULL, *GadToolsBase=NULL;
static BOOL SetupLibs(STRPTR *const errptr)
{
UtilityBase = (struct UTILITYBASE *)OpenLibrary("utility.library",0);
if (!UtilityBase) *errptr = OpenFailUtilBase;
CxBase = OpenLibrary("commodities.library",0);
if (!CxBase) *errptr = OpenFailCommBase;
GadToolsBase = OpenLibrary("gadtools.library",0);
if (!GadToolsBase) *errptr = OpenFailGadTBase;
return (BOOL)(UtilityBase && CxBase && GadToolsBase);
}
static void CleanupLibs(void)
{
CloseLibrary((struct Library *)UtilityBase);
CloseLibrary(CxBase);
CloseLibrary(GadToolsBase);
}
/* EventLoop():
* This is where our commodity does its work. This function receives
* CX messages and acts on them, mostly by making noises.
* If anything should go wrong, errptr is directed to an error string
* and the return value is set accordingly. If all is well, this should
* be RETURN_OK.
*/
static int EventLoop(STRPTR *const errptr,
CxObj *const brokerobj,
struct MsgPort *const cxport,
struct IOAudio *const soundrequest,
struct WindowContext *const PrefsWin)
{
const ULONG waitmask = SIGBREAKF_CTRL_C | (1<<(cxport->mp_SigBit));
/* --- */
for (;;)
{
struct Message *msg;
enum { win_unchanged, win_open, win_close } dowindow = win_unchanged;
const ULONG gotsig = Wait(waitmask|(PrefsWin->SigMask));
/* --- */
if (gotsig & SIGBREAKF_CTRL_C)
{
*errptr = Break_Exit;
return(RETURN_WARN);
}
while ((msg = GetMsg(cxport)))
{
CxMsg *const cxmsg = (CxMsg *)msg;
ULONG msgid = CxMsgID(cxmsg);
ULONG msgtype = CxMsgType(cxmsg);
BOOL clicknow = FALSE;
switch (msgtype)
{
case CXM_COMMAND: switch (msgid)
{
case CXCMD_DISABLE:
ActivateCxObj(brokerobj,FALSE);
break;
case CXCMD_ENABLE:
ActivateCxObj(brokerobj,TRUE);
break;
case CXCMD_KILL:
return(RETURN_OK);
case CXCMD_APPEAR:
case CXCMD_UNIQUE:
dowindow = win_open;
break;
case CXCMD_DISAPPEAR:
dowindow = win_close;
break;
}
break;
case CXM_IEVENT:
{
const struct InputEvent *const ievent =
(struct InputEvent *)CxMsgData(cxmsg);
if (!(ievent->ie_Code & IECODE_UP_PREFIX))
{
switch (ievent->ie_Class)
{
#ifndef NOCLICKMOUSE
case IECLASS_RAWMOUSE:
clicknow = ClickPrefs.ClickMouse;
break;
#endif /* NOCLICKMOUSE */
case IECLASS_RAWKEY:
clicknow = TRUE;
break;
default:
break;
}
}
}
break;
default:
break;
}
ReplyMsg(msg);
if (clicknow) KeyClick(soundrequest);
}
if (PrefsWin->Shown)
{
struct IntuiMessage *imsg;
/* --- */
while ((imsg = GT_GetIMsg(PrefsWin->Win->UserPort)))
{
const ULONG imsg_Class = imsg->Class;
const UWORD imsg_Code = imsg->Code;
const struct Gadget *const g = imsg->IAddress;
/* --- */
GT_ReplyIMsg(imsg);
switch (imsg_Class)
{
case IDCMP_GADGETDOWN:
case IDCMP_GADGETUP:
case IDCMP_MOUSEMOVE:
/* Note that this *looks* like a race condition; I don't think it
* is because we own the gadget, therefore it can only go away if
* we tell it to. Its GadgetID is supposed to remain constant as
* well so there can be no change to the GadgetID.
* Note that Intuition will not close the window before all
* intuimessages have been replied, so message arrival should not
* span reincarnations of our window.
*/
switch (g->GadgetID)
{
case mygadget_volume:
ClickPrefs.volume = imsg_Code;
ClickPrefs.newsettings = TRUE;
break;
case mygadget_cycles:
ClickPrefs.cycles = imsg_Code;
ClickPrefs.newsettings = TRUE;
break;
case mygadget_period:
ClickPrefs.period = SliderToPeriod(imsg_Code);
ClickPrefs.newsettings = TRUE;
break;
#ifndef NOCLICKMOUSE
case mygadget_clickmouse:
/* Another potential race condition; but this is one that
* IMO always invokes the desired behaviour. It occurs when
* the ClickMouse gadget is changed so fast in succession that
* its state is altered before we've processed the previous
* message. In that case the new state is used immediately.
*/
ClickPrefs.ClickMouse = (g->Flags & GFLG_SELECTED);
break;
#endif /* NOCLICKMOUSE */
default:
break;
}
break;
case IDCMP_CLOSEWINDOW:
dowindow = win_close;
break;
case IDCMP_REFRESHWINDOW:
GT_BeginRefresh(PrefsWin->Win);
GT_EndRefresh(PrefsWin->Win,TRUE);
break;
default:
break;
}
}
}
if (dowindow != win_unchanged)
{
if (dowindow == win_open)
{
ShowWindow(errptr,PrefsWin);
if (*errptr) return RETURN_FAIL;
}
else HideWindow(PrefsWin);
}
}
}
/* MatchStr():
* Boolean frontend for stricmp(). Returns TRUE if the strings pointed to by
* its arguments are identical (case-insensitive comparison), or FALSE if not.
*/
static BOOL MatchStr(const STRPTR a, const STRPTR b)
{
return (BOOL)(Stricmp((UBYTE *)a,(UBYTE *)b)==0);
}
/* BoolAttr():
* Returns whether a tooltype string should be interpreted as TRUE. Defaults to
* FALSE if no string is given, but TRUE if the string is empty.
* Hopefully this behaviour allows tooltypes to be set without arguments.
*/
static BOOL BoolAttr(const UBYTE *const value)
{
UBYTE *val = (UBYTE *)value;
if (val && (!*val || MatchStr(val,"TRUE") || MatchStr(val,"YES") ||
MatchStr(val,"ON")))
return TRUE;
else return FALSE;
}
int main(LONG argc, UBYTE **argv)
{
int returnval = RETURN_FAIL;
STRPTR error = NULL;
BYTE CX_Priority = 0;
BOOL cx_popup = FALSE;
struct NewBroker *mybroker;
struct IOAudio *soundrequest;
/* --- */
if (!SetupLibs(&error))
{
CleanupLibs();
if (error) PutStr(error);
return RETURN_FAIL;
}
ClickPrefs.period = HertzToPeriod(739);
ClickPrefs.volume = 50;
ClickPrefs.cycles = 1;
soundrequest = CreateSample(&error);
if (soundrequest)
{
if ((IconBase = OpenLibrary("icon.library",36)))
{
UBYTE **ToolTypes;
/* --- */
if ((ToolTypes=ArgArrayInit(argc,argv)))
{
/* Read tooltype settings for click sound. May be buggy (!?)
*/
ClickPrefs.period = HertzToPeriod(ArgInt(ToolTypes,"PITCH",739));
ClickPrefs.volume = ArgInt(ToolTypes,"VOLUME",50);
ClickPrefs.cycles = ArgInt(ToolTypes,"LENGTH",1);
#ifdef NOCLICKMOUSE
ClickPrefs.ClickMouse = FALSE;
#else /* NOCLICKMOUSE */
ClickPrefs.ClickMouse = BoolAttr(ArgString(ToolTypes,"CLICKMOUSE","NO"));
#endif /* NOCLICKMOUSE */
cx_popup = BoolAttr(ArgString(ToolTypes,"CX_POPUP","NO"));
ArgArrayDone();
}
CloseLibrary(IconBase);
}
else
{
DeleteSample(soundrequest);
PutStr(OpenFailIconBase);
return RETURN_FAIL;
}
/* A duration of zero means "infinite" to audio.device. */
if (!ClickPrefs.cycles) ClickPrefs.cycles = 1;
ClickPrefs.newsettings = TRUE;
mybroker = MakeBroker(&error, CX_Priority);
if (mybroker)
{
CxObj *brokerobj;
/* --- */
if ((brokerobj = SetupBroker(&error,mybroker)))
{
struct WindowContext *PrefsWin;
/* --- */
if ((PrefsWin = MakeWindow(&error,cx_popup)))
{
ActivateCxObj(brokerobj,TRUE);
returnval = EventLoop(&error, brokerobj, mybroker->nb_Port,
soundrequest, PrefsWin);
ActivateCxObj(brokerobj,FALSE);
DestroyWindow(PrefsWin);
}
DeleteCxObjAll(brokerobj);
}
KillBroker(mybroker);
}
DeleteSample(soundrequest);
}
if (error)
{
PutStr(error);
}
CleanupLibs();
return(returnval);
}